use chrono::DateTime;
use halo_model::{ExtensionOperator, GVK};
use sea_orm::ActiveValue::Set;
use sea_orm::{ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter};
use serde::Serialize;
use serde_json;

use crate::config::app_error::AppResult;
use crate::config::db::DB;
use crate::extension::index::extension::Comparators;
use crate::extension::index::index::indexed_query_engine;
use crate::extension::index::page_request::{PageRequest, PageRequestImpl};
use crate::extension::index::router::list_options::ListOptions;
use crate::extension::index::router::list_result::ListResult;
use crate::extension::index::scheme_manager::{
    self, build_store_name_str,  get_scheme, Scheme,
};
use crate::store::extension;
use crate::store::extension::Entity as ExtensionStore;
use crate::store::extension::Model;

pub async fn fetch<T>(struct_type: &str, name: &String) -> AppResult<T>
where
    T: for<'de> serde::Deserialize<'de> + ExtensionOperator+GVK,
{
    let db = get_db();

    // let name = build_store_name(s_type, name.clone()).await?;
    let (name, scheme) = get_scheme::<T>().await?;

    let extension_store = ExtensionStore::find()
        .filter(extension::Column::Name.eq(name))
        .one(db)
        .await?;

    if extension_store.is_none() {
        return Err(anyhow::anyhow!("extension_store 数据不存在").into());
    }
    let extension = extension_store.unwrap();

    convert_type(&scheme, &extension)
}

pub async fn fetch_or_none<T>(struct_type: &str, name: &String) -> AppResult<Option<T>>
where
    T: for<'de> serde::Deserialize<'de> + ExtensionOperator + GVK,
{
    let db = get_db();

    // let name = build_store_name(s_type, name.clone()).await?;
    let (name, scheme) = get_scheme::<T>().await?;

    let extension_store = ExtensionStore::find()
        .filter(extension::Column::Name.eq(name))
        .one(db)
        .await?;

    if extension_store.is_none() {
        return Ok(None);
    }
    let extension = extension_store.unwrap();

    match convert_type(&scheme, &extension) {
        Ok(v) => Ok(Some(v)),
        Err(e) => Ok(None),
    }
}

pub async fn list<T>(struct_type: &str, names: Vec<String>) -> AppResult<Vec<T>>
where
    T: for<'de> serde::Deserialize<'de> + halo_model::GVK,
{
    if names.is_empty() {
        return Ok(vec![]);
    }

    let mut new_names: Vec<String> = Vec::new();
    for name in names {
        let true_name = build_store_name_str::<T>(&name).await?;
        new_names.push(true_name);
    }

    let db = get_db();
    let extension_store = ExtensionStore::find()
        .filter(extension::Column::Name.is_in(new_names))
        .all(db)
        .await?;
    let mut res = vec![];
    for extension in extension_store {
        let data = extension.data;
        match serde_json::from_slice(&data) {
            Ok(v) => res.push(v),
            Err(e) => return Err(anyhow::anyhow!(e.to_string()).into()),
        }
    }
    Ok(res)
}

pub async fn list_filter<T, P>(kind: &str, predicate: P) -> AppResult<Vec<T>>
where
    T: for<'de> serde::Deserialize<'de> + ExtensionOperator + halo_model::GVK,
    P: Fn(&T) -> bool,
{
    let (name, scheme) = get_scheme::<T>().await?;

    let db = get_db();
    let extension_store = ExtensionStore::find()
        .filter(extension::Column::Name.starts_with(name))
        .all(db)
        .await?
        .iter()
        .map(|it| convert_type(&scheme, it).unwrap())
        .filter(|x| predicate(x))
        .collect::<Vec<T>>();

    Ok(extension_store)
}

pub async fn list_filter_comparator<T, P>(
    kind: &str,
    predicate: P,
    comparators: Comparators,
) -> AppResult<Vec<T>>
where
    T: for<'de> serde::Deserialize<'de> + ExtensionOperator + halo_model::GVK,
    P: Fn(&T) -> bool,
{
    let (name, scheme) = get_scheme::<T>().await?;

    let db = get_db();
    let extension_store = ExtensionStore::find()
        .filter(extension::Column::Name.starts_with(name))
        .all(db)
        .await?
        .iter()
        .map(|it| convert_type(&scheme, it).unwrap())
        .collect::<Vec<T>>();

    let mut extension_store = {
        let mut res = vec![];
        for extension in extension_store {
            if predicate(&extension) {
                res.push(extension);
            }
        }
        res
    };

    extension_store.sort_by(Comparators::comparing(comparators));

    Ok(extension_store)
}

pub(crate) async fn list_by<T>(
    kind: &str,
    list_options: &ListOptions,
    page_request: &PageRequestImpl,
) -> AppResult<ListResult<T>>
where
    T: for<'de> serde::Deserialize<'de> + ExtensionOperator + Clone + GVK,
{
    // TODO: list_by
    let (name, schema) = get_scheme::<T>().await?;

    let object_keys = indexed_query_engine::retrieve::<T>(
        &schema.group_version_kind,
        list_options,
        page_request,
    )?;

    let items = &object_keys.items;
    let mut store_names = Vec::new();
    for object_key in items {
        let store_name = scheme_manager::build_store_name(&schema, &object_key);
        store_names.push(store_name);
    }
    let list = list_by_names::<T>(&store_names).await?;
    Ok(ListResult::new(
        page_request.get_page_number(),
        page_request.get_page_size(),
        object_keys.total,
        list,
    ))
}

pub(crate) async fn list_by_names<T>(names: &Vec<String>) -> AppResult<Vec<T>>
where
    T: for<'de> serde::Deserialize<'de>,
{
    let db = get_db();
    let mut extension_store = ExtensionStore::find()
        .filter(extension::Column::Name.is_in(names))
        .all(db)
        .await?;
    extension_store.sort_by_key(|store| {
        names
            .iter()
            .position(|n| n == &store.name)
            .unwrap_or(usize::MAX)
    });
    let mut res = vec![];
    for extension in extension_store {
        let data = extension.data;
        match serde_json::from_slice(&data) {
            Ok(v) => res.push(v),
            Err(e) => return Err(anyhow::anyhow!(e.to_string()).into()),
        }
    }
    Ok(res)
}

pub(crate) async fn update<T>(mut extension_store: T) -> AppResult<()>
where
    T: for<'de> serde::Deserialize<'de> + ExtensionOperator + Serialize + halo_model::GVK,
{
    let kind = extension_store.get_kind();

    let old_extension: T = fetch(&kind, &extension_store.get_metadata().get_name()).await?;
    let old_metadata = old_extension.get_metadata();
    let mut new_metadata = extension_store.get_metadata().clone();
    new_metadata.set_creation_timestamp(old_metadata.get_creation_timestamp());
    new_metadata.set_generate_name(old_metadata.get_generate_name());
    extension_store.set_metadata(new_metadata);
    // var onlyStatusChanged =
    //     isOnlyStatusChanged(oldJsonExt.getInternal(), newJsonExt.getInternal());
    //
    // var store = this.converter.convertTo(newJsonExt);
    // var updated = doUpdate(extension_index, store.getName(), store.getVersion(), store.getData());
    // if (!onlyStatusChanged) {
    //     updated = updated.doOnNext(ext -> watchers.onUpdate(old, ext));
    // }

    let model = convert_to_model(&extension_store).await?;
    do_update(model).await;
    Ok(())
}

pub(crate) async fn convert_to_model<T>(extension: &T) -> AppResult<Model>
where
    T: for<'de> serde::Deserialize<'de> + ExtensionOperator + Serialize + halo_model::GVK,
{
    let json = serde_json::to_vec(extension)?;

    let store_name =
        build_store_name_str::<T>(&extension.get_metadata().get_name()).await?;

    let version = extension.get_metadata().get_version().unwrap_or(0);

    Ok(Model {
        name: store_name,
        data: json,
        version,
    })
}

pub(crate) async fn convert_to_entity_model<T>(extension: &T) -> AppResult<extension::ActiveModel>
where
    T: for<'de> serde::Deserialize<'de> + ExtensionOperator + Serialize + halo_model::GVK,
{
    let json = serde_json::to_vec(extension)?;

    let store_name =
        build_store_name_str::<T>(&extension.get_metadata().get_name()).await?;

    let version = extension.get_metadata().get_version().unwrap_or(0);

    Ok(extension::ActiveModel {
        name: Set(store_name),
        data: Set(json),
        version: Set(version),
    })
}

pub(crate) async fn do_update(extension_store: Model) {
    let db = get_db();

    let update: extension::ActiveModel = extension_store.into();
    update.reset_all().update(db).await.unwrap();
    // let extension_store: extension::index::Model = update.clone().update(db).await.unwrap();
}

pub(crate) async fn delete<T>(mut extension_store:  T) -> AppResult<()>
where
    T: for<'de> serde::Deserialize<'de> + ExtensionOperator + Serialize + halo_model::GVK,
{
    extension_store
        .get_metadata_mut()
        .set_deletion_timestamp(DateTime::default());

    let model = convert_to_model(&extension_store).await?;
    do_update(model).await;
    Ok(())
}

pub(crate) async fn create<T>(extension_store: &mut T) -> AppResult<()>
where
    T: for<'de> serde::Deserialize<'de> + ExtensionOperator + Serialize + halo_model::GVK,
{
    let mut metadata = extension_store.get_metadata_mut();
    metadata.set_deletion_timestamp(DateTime::default());
    

    let model = convert_to_entity_model(extension_store).await?;

    do_create(model).await?;
    Ok(())
}

async fn do_delete(extension_store: Model) {
    let db = get_db();
    let update: extension::ActiveModel = extension_store.into();
    update.delete(db).await.unwrap();
}

async fn do_create(extension_store: extension::ActiveModel) -> AppResult<()> {
    let db = get_db();
    ExtensionStore::insert(extension_store).exec(db).await?;
    Ok(())
}

fn convert_type<T>(scheme: &Scheme, extension: &Model) -> AppResult<T>
where
    T: for<'de> serde::Deserialize<'de> + ExtensionOperator,
{
    match serde_json::from_slice(&extension.data) {
        Ok(mut v) => {
            let mut v: T = v;
            // let new_gvk = GVK {
            //     group: scheme.group_version_kind.group.clone(),
            //     version: scheme.group_version_kind.version.clone(),
            //     kind: scheme.group_version_kind.kind.clone(),
            //     singular: scheme.singular.clone(),
            //     plural: scheme.plural.clone(),
            // };
            v.set_kind(scheme.group_version_kind.kind.clone());
            v.set_api_version(scheme.group_version_kind.version.clone());
            v.get_metadata_mut().set_version(extension.version);
            Ok(v)
        }
        Err(e) => Err(anyhow::anyhow!(e.to_string()).into()),
    }
}

fn get_db<'a>() -> &'a DatabaseConnection {
    let db = DB
        .get()
        .ok_or(anyhow::anyhow!("获取数据库连接失败"))
        .unwrap();
    db
}

#[allow(unused_imports)]
mod tests {
    use crate::extension::model::role_binding::Subject;

    fn create_filter(kind: String, api_group: String) -> Box<dyn FnMut(&Subject) -> bool> {
        Box::new(move |subject: &Subject| {
            subject.kind == kind.clone() && subject.api_group.clone() == api_group
        })
    }

    #[tokio::test]
    async fn closure_filter() {
        pub fn search_lines<'a>(query: &str, content: &'a str, insensitive: bool) -> Vec<&'a str> {
            let lines = content.lines();

            let condition_intensive;
            let mut condition: &dyn Fn(&&str) -> bool =
                &|line: &&str| -> bool { line.contains(query) };

            if insensitive {
                condition_intensive =
                    |line: &&str| -> bool { line.to_lowercase().contains(&query.to_lowercase()) };
                condition = &condition_intensive;
            };

            lines.filter(condition).collect()
        }
    }
}
